package idlrpc

import (
	"gitee.com/CloudGuan/rpc-go-backend/idlrpc/net"
	"gitee.com/CloudGuan/rpc-go-backend/idlrpc/transport"
)

var (
	connMap map[uint64]*RpcConnHandle
)

type RpcListenHandle struct {
}

type RpcConnHandle struct {
	connId  uint64 //网络层赋值，不同网络库不同实现
	conn    net.IdlConn
	trans   transport.Transport
	msgchan chan []byte
}

func init() {
	connMap = make(map[uint64]*RpcConnHandle)
}

func GetConnMaps() *map[uint64]*RpcConnHandle {
	return &connMap
}

func (rpc *RpcListenHandle) OnAccept(conn net.IdlConn) bool {
	if conn == nil {
		return false
	}

	//检查是否id重复 重复关闭旧的
	if old, ok := connMap[conn.GetConnID()]; ok {
		old.conn.Close()
		old.trans.Close()
	}

	trans := transport.NewTransportRing()
	if trans == nil {
		return false
	}

	rc := &RpcConnHandle{
		connId:  conn.GetConnID(),
		conn:    conn,
		trans:   trans,
		msgchan: make(chan []byte),
	}

	conn.SetHandle(rc)
	connMap[conn.GetConnID()] = rc
	return true
}

func (rc *RpcConnHandle) OnConnect(conn net.IdlConn) bool {
	//检查connid 的是否重复，理论上要关闭旧的 替换新的
	if old, ok := connMap[conn.GetConnID()]; ok {
		old.conn.Close()
	}

	trans := transport.NewTransportRing()
	if trans == nil {
		return false
	}

	rc.conn = conn
	rc.connId = conn.GetConnID()
	rc.trans = trans
	conn.SetHandle(rc)
	return true
}

func (rc *RpcConnHandle) OnRecv(pkg []byte) bool {
	if rc.trans == nil {
		return false
	}

	if rc.msgchan == nil {
		return false
	}

	//拷贝一份 这里要发拷贝的 slice, 不然网络协程里重新接收会把数据写坏
	sendpkg := make([]byte, len(pkg))
	copy(sendpkg, pkg)
	//rc.trans.Wirte(pkg, len(pkg))
	rc.msgchan <- sendpkg
	return true
}

func (rc *RpcConnHandle) Tick() int {
	if rc.msgchan == nil {
		return -1
	}

	select {
	case msg, more := <-rc.msgchan:
		if len(msg) == 0 {
			return -1
		}
		if more == false {
			//表示chan已经关闭
			return -1
		}
		rc.trans.Wirte(msg, len(msg))
		return len(msg)
	default:
		return 0
	}
}

func (rc *RpcConnHandle) GetTrans() transport.Transport {
	return rc.trans
}

func (rc *RpcConnHandle) OnClose() {
	if rc.conn == nil {
		return
	}

	delete(connMap, rc.connId)
	rc.trans.Close()
	rc.connId = 0
	rc.trans = nil
	rc.conn = nil
	close(rc.msgchan)
	//rc.msgchan = nil
}
